package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.date.DateUtil;
import com.deer.wms.busine.tactic.model.WaveTacticDianshang;
import com.deer.wms.busine.tactic.model.WaveTacticDianshangCriteria;
import com.deer.wms.busine.tactic.model.WaveTacticDianshangDto;
import com.deer.wms.busine.tactic.service.WaveTacticDianshangService;
import com.deer.wms.busine.tactic.service.WaveTacticService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BillNoUtils;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.system.manage.constant.SystemManageConstant;
import com.deer.wms.system.manage.model.ware.WareInfo;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.system.manage.service.WareInfoService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.WaveMasterMapper;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.SO.SoMaster;
import com.deer.wms.ware.task.model.SO.SoMasterCriteria;
import com.deer.wms.ware.task.model.SO.SoMasterDto;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.Wave.WaveMaster;
import com.deer.wms.ware.task.model.Wave.WaveMasterCriteria;
import com.deer.wms.ware.task.model.Wave.WaveMasterDto;
import com.deer.wms.ware.task.service.SoDetailService;
import com.deer.wms.ware.task.service.SoMasterService;
import com.deer.wms.ware.task.service.WaveDetailService;
import com.deer.wms.ware.task.service.WaveMasterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author ll
 * @since 2020/02/02
 */
@Service
@Transactional
public class WaveMasterServiceImpl extends SuperServiceImpl<WaveMasterMapper, WaveMaster> implements WaveMasterService {

    @Autowired
    private WaveTacticService waveTacticService;
    @Autowired
    private SoMasterService soMasterService;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private WareInfoService wareInfoService;
    @Autowired
    private WaveMasterMapper waveMasterMapper;
    @Autowired
    private WaveTacticDianshangService waveTacticDianshangService;
    @Autowired
    private CodeRuleService codeRuleService;


    @Autowired
    private SoDetailService soDetailService;

    /**
     * 生成波次 <p>
     * 不同的仓库，波次策略不一样
     * @return boolean
     */
    @Override
    public boolean generateWaves() {
        String now = DateUtils.getNowDateTimeString();

        // 查询激活的波次策略
        WaveTacticDianshangCriteria criteria = new WaveTacticDianshangCriteria();
        criteria.setState(1);
        List<WaveTacticDianshangDto> tactics = waveTacticDianshangService.findList(criteria);

        if (tactics == null || tactics.size() == 0) {
            System.out.println("没有激活的波次策略！");
            return false;
        }

        // 根据每条策略生成波次
        for (WaveTacticDianshang waveTactic : tactics) {
            //根据波次策略中的条件
            SoMasterCriteria soMasterCriteria = generateSoMasterCriteria(waveTactic);
            List<SoMaster> soMasters = soMasterService.findSoByWave(soMasterCriteria);

            //线程每时每刻都在刷新，同一个波次策略生成波次只能在设置的最大分钟数内，否则该策略的下一个波次
            Integer maxTime = waveTactic.getMaxWaitTime();
            //判断是否已生成最新的波次
            WaveMaster last = waveMasterMapper.getLast(waveTactic.getWaveTacticCode());
            String nowTime = DateUtils.getNowDateTimeString();
            //如果波次已存在，获取波次的生成时间，如果波次未生成，获取当前时间
            String lastTime = last == null ? nowTime : last.getCreateTime();
            //获取时间差值，分别处理
            Long durationTime = DateUtils.getMin(lastTime, nowTime);
            if (last != null && durationTime >= maxTime) {
                //超出等待时间，状态改为待拣货
                last.setState(1);
                this.updateById(last);
            }
            if (last != null && last.getTotalBillCount() >= waveTactic.getSoCountLimit()) {
                //超过SO订单数，不能再合波次，状态改为待拣货
                last.setState(1);
                this.updateById(last);
            }
            if (last != null && last.getTotalSkuCount() >= waveTactic.getItemCount()) {
                //超过SKU数，不能再合波次，状态改为待拣货
                last.setState(1);
                this.updateById(last);
            }
            if (soMasters.size() > 0) {
                //该策略第一次生成  或者 该波次要生成下一个波次
                if (waveTactic.getLastTime() == null || durationTime >= maxTime || last == null) {
                    //生成新的波次
                    WareInfo ware = wareInfoService.getById(waveTactic.getWareId());
                    WaveMaster waveMaster = new WaveMaster();
                    waveMaster.setCreateTime(now);
                    waveMaster.setCode(BillNoUtils.generateWaveCode(waveTactic.getWareId()));
                    waveMaster.setWareId(waveTactic.getWareId());
                    waveMaster.setWareName(ware.getWareName());
                    waveMaster.setWaveTacticCode(waveTactic.getWaveTacticCode());
                    waveMaster.setTotalSkuCount(0);
                    waveMaster.setTotalBillCount(0);

                    soMasters:
                    for (SoMaster soMaster : soMasters) {
                        Integer count = waveMasterMapper.countSku(waveMaster.getWaveId(), soMaster.getSoMasterId()).size();
                        if (count > waveTactic.getItemCount() || waveMaster.getTotalBillCount() >= waveTactic.getSoCountLimit()) {
                            if (waveMaster.getWaveId() != null) {
                                waveMaster.setState(1);
                                this.updateById(waveMaster);
                            }
                        } else {
                            waveMaster.setTotalSkuCount(count);
                            waveMaster.setTotalBillCount(waveMaster.getTotalBillCount() + 1);
                            if (waveMaster.getWaveId() == null) {
                                waveTactic.setLastTime(nowTime);
                                waveTacticDianshangService.updateById(waveTactic);
                                save(waveMaster);
                            } else {
                                this.updateById(waveMaster);
                            }
                            WaveDetail waveDetail = new WaveDetail();
//                            waveDetail.setSoMasterId(soMaster.getSoMasterId());
                            waveDetail.setWaveMasterId(waveMaster.getWaveId());
                            waveDetailService.save(waveDetail);
                        }
                    }
                } else {
                    //不需要生成新的波次
                    List<WaveDetail> list = waveDetailService.getByMasterId(last.getWaveId());
                    Integer soCount = list.size() - 1;
                    soMasters:
                    for (SoMaster soMaster : soMasters) {
                        soCount += 1;
                        Integer count = waveMasterMapper.countSku(last.getWaveId(), soMaster.getSoMasterId()).size();
                        if (count > waveTactic.getItemCount() || soCount >= waveTactic.getSoCountLimit()) {
                            //超过SKU限制
                            last.setState(1);
                        } else {
                            WaveDetail waveDetail = new WaveDetail();
//                            waveDetail.setSoMasterId(soMaster.getSoMasterId());
                            waveDetail.setWaveMasterId(last.getWaveId());
                            waveDetailService.save(waveDetail);
                            last.setTotalSkuCount(count);
                            last.setTotalBillCount(last.getTotalBillCount() + 1);
                        }
                        this.updateById(last);
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void waveState() {
        //找到状态在 0(订单接收中) ~ 4(发运完成) 之间的波次
        List<WaveMaster> list = findByStateNo0();

        waveMaster:
        for (WaveMaster waveMaster : list) {
            //已分配  正在拣货中的SO数量
            Integer count4 = soMasterService.findCountByWaveIdAndState(waveMaster.getWaveId(), WareTaskConstant.SO_STATE_ASSIGNED);
            //拣货完成SO数量
            Integer count6 = soMasterService.findCountByWaveIdAndState(waveMaster.getWaveId(), WareTaskConstant.SO_STATE_PICKED);
            //复核完成的SO数量
            Integer count7 = soMasterService.findCountByWaveIdAndState(waveMaster.getWaveId(), WareTaskConstant.SO_STATE_CHECKED);
            //发运完成的SO数量
            Integer count8 = soMasterService.findCountByWaveIdAndState(waveMaster.getWaveId(), WareTaskConstant.SO_STATE_OUTED);

            //拣货中的为0 拣货完成的大于0
            if (count4 == 0 && count6 > 0) {
                //拣货完成
                waveMaster.setState(WareTaskConstant.WAVE_STATE_PICKED);
                this.updateById(waveMaster);
            }

            //拣货完成的为0 复核完成的大于0
            if (count6 == 0 && count7 > 0) {
                //播种完成 || 复核完成
                waveMaster.setState(WareTaskConstant.WAVE_STATE_CHECKED);
                this.updateById(waveMaster);
            }

            //复核完成的为0 发运完成的大于0
            if (count7 == 0 && count8 > 0) {
                //发运完成
                waveMaster.setState(WareTaskConstant.WAVE_STATE_SEND);
                this.updateById(waveMaster);
            }
        }
    }

    @Override
    public List<WaveMaster> findByState(Integer state) {
        return waveMasterMapper.findByState(state);
    }


    @Override
    public List<WaveMaster> findByStateNo0(   ) {
        return waveMasterMapper.findByStateNo0();
    }

    @Override
    public List<WaveMasterDto> findList(WaveMasterCriteria criteria) {
        return waveMasterMapper.findList(criteria);
    }
    @Override
    public List<WaveMasterDto> allotWave(WaveMasterCriteria criteria) {
        return waveMasterMapper.allotWave(criteria);
    }

    @Override
    public WaveMaster mergeSo(List<SoMasterDto> soMasterDtoList, CurrentUser currentUser) {
        WaveMaster waveMaster = null;
        List<WaveDetail> waveDetailList = new ArrayList<>();

        //汇总出库任务明细，统一处理
        List<SoDetail> soDetailList = new ArrayList<>();
        List<SoMaster> soMasterList = new ArrayList<>();

        //Step1.根据某一条出库任务生成波次
        for (SoMasterDto soMasterDto : soMasterDtoList) {
            //只会执行一次
            if (waveMaster == null) {
                waveMaster = new WaveMaster();
                //波次号
                waveMaster.setCode(codeRuleService.generateCode(SystemManageConstant.CODE_RULE_WAVE));
                //创建人 时间
                waveMaster.setAllotUserId(currentUser.getUserId());
                waveMaster.setAllotUserName(currentUser.getUserName());
                waveMaster.setAllotTime(DateUtil.now());
                waveMaster.setCreateTime(DateUtil.now());
                //状态(新建) 仓库
                waveMaster.setState(WareTaskConstant.WAVE_STATE_PROCESSING);
                waveMaster.setWareId(soMasterDto.getWareId());
                waveMaster.setWareName(soMasterDto.getWareName());
                //单据号数和SKU数
                waveMaster.setTotalBillCount(soMasterDtoList.size());
            }
            //出库任务信息更新：记录其关联的波次编码，修改状态
            SoMaster soMaster = soMasterService.getById(soMasterDto.getSoMasterId());
            soMaster.setWaveCode(waveMaster.getCode());
            soMaster.setState(WareTaskConstant.SO_STATE_PROCESSING);
            //添加进明细集合，下一步骤一并处理
            soMasterList.add(soMaster);
            soDetailList.addAll(soDetailService.findByBillNo(soMaster.getBillNo()));
        }
        this.save(waveMaster);

        //Step2.生成波次明细
        //按照出库任务明细的物料，汇总数量
        Map<String, List<SoDetail>> map = soDetailList.stream().collect(Collectors.groupingBy(SoDetail::getItemCode));
        Set<String> keys = map.keySet();
        int rowNum = 1; //波次明细的编码
        for (String key : keys) {
            List<SoDetail> soDetails = map.get(key);
            WaveDetail waveDetail = null;
            double qty = 0.0;
            for (SoDetail soDetail : soDetails) {
                if (waveDetail == null) {
                    waveDetail = new WaveDetail(soDetail);
                    //波次单信息
                    waveDetail.setWaveMasterId(waveMaster.getWaveId());
                    waveDetail.setWaveCode(waveMaster.getCode());
                    waveDetail.setWareId(waveMaster.getWareId());
                    waveDetail.setWareName(waveMaster.getWareName());
                    waveDetailService.save(waveDetail);
                }
                //汇总数量
                qty += soDetail.getOrderQuantity();
                soDetail.setWaveDetailId(waveDetail.getWaveDetailId());
                //soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_PART_SEND);
            }
            waveDetail.setQuantity(qty);
            waveDetail.setAllottedQuantity(0.0);
            waveDetail.setPickQuantity(0.0);
            waveDetail.setWaveDetailCode(waveMaster.getCode() + "*" + rowNum);
            rowNum++;

            waveDetailList.add(waveDetail);
        }
        waveMaster.setTotalSkuCount(keys.size());

//        if (true) {throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR,"ddd");}
        this.updateById(waveMaster);
        waveDetailService.updateBatchById(waveDetailList);
        soMasterService.updateBatchById(soMasterList);
        soDetailService.updateBatchById(soDetailList);

        return waveMaster;
    }

    /**
     * 根据波次策略生成SO的查询条件
     * @param waveTactic 波次策略
     * @return SoMasterCriteria
     */
    private SoMasterCriteria generateSoMasterCriteria(WaveTacticDianshang waveTactic) {
        SoMasterCriteria criteria = new SoMasterCriteria();
        //仓库
        if (waveTactic.getWareId() != null) {
            criteria.setWareId(waveTactic.getWareId());
        } else {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "波次策略无仓库属性");
        }
        //客户
        if (waveTactic.getCustomerId() != null && waveTactic.getCustomerId() != 0) {
            criteria.setCustomerId(waveTactic.getCustomerId());
        }
        //承运商
        if (waveTactic.getCarrierId() != null && waveTactic.getCarrierId() != 0) {
            criteria.setCarrierId(waveTactic.getCarrierId());
        }
        //SO类型
        if (waveTactic.getSoType() != null ) {
            criteria.setSoType(waveTactic.getSoType());
        }
        //物料种类 SKU数
        if (waveTactic.getItemCount() != null) {
            criteria.setWaveItemCount(waveTactic.getItemCount());
        }
        //订单结构
        if (waveTactic.getSoStructure() != null) {
            criteria.setSoStructure(waveTactic.getSoStructure());
        }
        return criteria;
    }
}
